package com.sanji.capture_audio.service

import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.telecom.Call
import android.telecom.InCallService
import android.util.Log
import com.sanji.capture_audio.utils.Preferences
import com.sanji.capture_audio.utils.NotificationHelper
import com.sanji.capture_audio.utils.Permissions
import com.sanji.capture_audio.thread.PlayerThread
import com.sanji.capture_audio.thread.RecorderThread


/**
 * 通话服务类，用于在来电时播放预录的音频文件
 * 该服务继承自 InCallService，可以监听和管理通话状态
 */
class PlayerInCallService : InCallService(), 
    PlayerThread.OnPlaybackCompletedListener, 
    RecorderThread.OnRecordingCompletedListener {
    companion object {
        // 日志标签
        private val TAG = PlayerInCallService::class.java.simpleName
    }

    // 主线程处理器
    private val handler = Handler(Looper.getMainLooper())
    // 用户偏好设置
    private lateinit var prefs: Preferences
    // 通知帮助类
    private lateinit var notificationHelper: NotificationHelper

    /**
     * 每个活动通话的播放器线程。当通话断开连接时，它会立即从该映射中移除，
     * 并且 [pendingExit] 会增加。
     */
    private val players = HashMap<Call, PlayerThread>()

    /**
     * 每个活动通话的录音线程。当通话断开连接时，它会立即从该映射中移除，
     * 并且 [pendingExit] 会增加。
     */
    private val recorders = HashMap<Call, RecorderThread>()

    /**
     * 通话断开连接后等待退出的线程数。如果播放器线程在通话断开之前失败，
     * 这个值可能是负数。
     */
    private var pendingExit = 0

    /**
     * 通话状态变化回调
     * 监听通话状态的变化，当状态改变时调用 handleStateChange 方法
     */
    private val callback = object : Call.Callback() {
        override fun onStateChanged(call: Call, state: Int) {
            super.onStateChanged(call, state)
            Log.d(TAG, "onStateChanged: $call, $state")

            handleStateChange(call)
        }
    }

    // 服务创建时初始化偏好设置和通知帮助类
    override fun onCreate() {
        super.onCreate()

        prefs = Preferences(this)
        notificationHelper = NotificationHelper(this)
    }

    /**
     * 当有新通话加入时调用
     * @param call 新加入的通话
     */
    override fun onCallAdded(call: Call) {
        super.onCallAdded(call)
        Log.d(TAG, "onCallAdded: $call")

        call.registerCallback(callback)
        handleStateChange(call)
    }

    /**
     * 当通话被移除时调用
     * @param call 被移除的通话
     */
    override fun onCallRemoved(call: Call) {
        super.onCallRemoved(call)
        Log.d(TAG, "onCallRemoved: $call")

        call.unregisterCallback(callback)
        handleStateChange(call)
    }

    /**
     * 当通话变为活动状态时启动新的播放器线程，当通话断开时取消它。
     *
     * 当通话断开时，通话会从 [players] 中移除，[pendingExit] 会增加。
     * 当线程实际完成时，[pendingExit] 会减少，如果发生错误，这可能在通话断开之前。
     * 
     * @param call 状态发生变化的通话
     */
    private fun handleStateChange(call: Call) {
        val state = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            call.details.state
        } else {
            @Suppress("DEPRECATION")
            call.state
        }

        if (state == Call.STATE_ACTIVE) {
            if (!prefs.isEnabled) {
                Log.v(TAG, "通话音频播放已禁用")
            // } else if (!Permissions.haveRequired(this)) {
            //     Log.v(TAG, "尚未授予所需权限")
            } else if (!players.containsKey(call)) {
                // 播放开始时发送通知
                notificationHelper.showNotification(
                    "录音播放开始",
                    "正在播放录音文件...",
                    NotificationHelper.NOTIFICATION_ID_START
                )
                Log.v(TAG, "开始播放")
                val player = PlayerThread(this, this, call)
                players[call] = player

                updateForegroundState()
                player.start()
            }

            // 处理录音功能
            if (!prefs.isRecordingEnabled) {
                Log.v(TAG, "通话录音已禁用")
            } else if (!recorders.containsKey(call)) {
                // 录音开始时发送通知
                notificationHelper.showNotification(
                    "通话录音开始",
                    "正在录制通话...",
                    NotificationHelper.NOTIFICATION_ID_START + 100
                )
                Log.v(TAG, "开始录音")
                val recorder = RecorderThread(this, this, call)
                recorders[call] = recorder

                updateForegroundState()
                recorder.start()
            }            
        } else if (state == Call.STATE_DISCONNECTING || state == Call.STATE_DISCONNECTED) {
            val player = players[call]
            if (player != null) {
                player.cancel()

                players.remove(call)

                // 在线程退出之前不要更改前台状态
                ++pendingExit
            }

            // 处理录音器
            val recorder = recorders[call]
            if (recorder != null) {
                recorder.cancel()
                recorders.remove(call)
                ++pendingExit
            }
        }
    }

    /**
     * 当有活动通话或播放器/录音器线程尚未完成退出时，移动到前台并创建持久通知。
     */
    private fun updateForegroundState() {
        // 如果有正在播放/录音的通话或有待退出的线程，则将服务置于前台
        if (players.isNotEmpty() || recorders.isNotEmpty() || pendingExit > 0) {
            // 创建前台服务通知
            val notification = notificationHelper.createPersistentNotification()
            startForeground(NotificationHelper.NOTIFICATION_ID_PERSISTENT, notification)
        } else {
            // 没有活动通话且没有待退出线程时，停止前台服务
            stopForeground(true)
        }
    }   

    /**
     * 线程退出处理方法
     * 减少待退出线程计数并更新前台状态
     */
    private fun onThreadExited() {
        --pendingExit
        updateForegroundState()
    }

    /**
     * 播放完成回调方法
     * 当 PlayerThread 完成音频播放时调用此方法
     * @param thread 完成播放的线程
     */
    override fun onPlaybackCompleted(thread: PlayerThread) {
        handler.post {
            Log.i(TAG, "播放完成: ${thread.id}")
            // 播放完成时发送通知
            notificationHelper.showNotification(
                "录音播放结束",
                "录音文件播放已完成",
                NotificationHelper.NOTIFICATION_ID_END
            )
            onThreadExited()
        }
    }
    
    /**
     * 播放失败回调方法
     * 当 PlayerThread 播放音频失败时调用此方法
     * @param thread 播放失败的线程
     * @param errorMsg 错误信息
     */
    override fun onPlaybackFailed(thread: PlayerThread, errorMsg: String?) {
        handler.post {
            Log.w(TAG, "播放失败: ${thread.id}: $errorMsg")
            onThreadExited()
            // 播放失败时发送通知
            notificationHelper.showNotification(
                "录音播放失败",
                errorMsg ?: "未知错误",
                NotificationHelper.NOTIFICATION_ID_FAILED
            )
        }
    }

    /**
     * 录音完成回调方法
     * 当 RecorderThread 完成音频录音时调用此方法
     * @param thread 完成录音的线程
     */
    override fun onRecordingCompleted(thread: RecorderThread) {
        handler.post {
            Log.i(TAG, "录音完成: ${thread.id}")
            // 录音完成时发送通知
            notificationHelper.showNotification(
                "通话录音结束",
                "通话录音已完成",
                NotificationHelper.NOTIFICATION_ID_END + 100
            )
            onThreadExited()
        }
    }

    /**
     * 录音失败回调方法
     * 当 RecorderThread 录音音频失败时调用此方法
     * @param thread 录音失败的线程
     * @param errorMsg 错误信息
     */
    override fun onRecordingFailed(thread: RecorderThread, errorMsg: String?) {
        handler.post {
            Log.w(TAG, "录音失败: ${thread.id}: $errorMsg")
            onThreadExited()
            // 录音失败时发送通知
            notificationHelper.showNotification(
                "通话录音失败",
                errorMsg ?: "未知错误",
                NotificationHelper.NOTIFICATION_ID_FAILED + 100
            )
        }
    } 
}